import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 1. 读取CSV文件（需替换为实际路径）
#file_path = r'd:\dataset\广播电视情况.csv'  # 原始字符串避免转义问题
#df = pd.read_csv(file_path)
df = pd.read_csv('d:/dataset/广播电视情况.csv',header=0)
# =============================================================================
# 一、缺失值检查与处理
# =============================================================================

# 2. 缺失值统计（按列显示缺失数量和比例）
def check_missing_values(df):
    missing = df.isnull().sum()  # 各列缺失值数量
    missing_ratio = (missing / len(df)) * 100  # 缺失比例
    missing_df = pd.concat([missing, missing_ratio], axis=1)
    missing_df.columns = ['缺失数量', '缺失比例(%)']
    return missing_df

missing_report = check_missing_values(df)
print("【缺失值统计报告】\n", missing_report)

# 3. 缺失值可视化（热力图）
plt.figure(figsize=(12, 6))
sns.heatmap(df.isnull(), cbar=False, cmap='viridis', yticklabels=False)
plt.title('缺失值分布热力图')
plt.show()

# 4. 缺失值处理策略
# 场景1：数值型列（如票房收入）用均值/中位数填充
numeric_cols = df.select_dtypes(include=[np.number]).columns  # 提取数值型列
df[numeric_cols] = df[numeric_cols].fillna(df[numeric_cols].median())  # 用中位数填充

# 场景2：字符型列（如指标名称）用众数或删除（若缺失比例过高）
categorical_cols = df.select_dtypes(include=['object']).columns
for col in categorical_cols:
    if df[col].isnull().sum() > 0:
        mode_value = df[col].mode()[0]  # 计算众数
        df[col] = df[col].fillna(mode_value)

# =============================================================================
# 二、异常值检查与处理
# =============================================================================

# 5. 异常值检测（统计方法：Z-score法，适用于正态分布数据）
from scipy import stats

def detect_outliers_zscore(df, threshold=3):
    z_scores = np.abs(stats.zscore(df[numeric_cols]))
    outliers = (z_scores > threshold).any(axis=1)
    return df[outliers]

outliers_zscore = detect_outliers_zscore(df)
print("\n【Z-score检测到的异常值数量】:", len(outliers_zscore))

# 6. 异常值检测（箱线图可视化，适用于非正态分布数据）
plt.figure(figsize=(15, 8))
df[numeric_cols].boxplot()
plt.title('数值型变量箱线图（异常值用红色点标注）', fontsize=14)
plt.xticks(rotation=45)
plt.show()

# 7. 异常值处理策略
# 方法1：截断法（将异常值替换为分位数边界）
def winsorize_column(column, lower=0.01, upper=0.99):
    """将列中数值截断至指定分位数范围内"""
    q_low = column.quantile(lower)
    q_high = column.quantile(upper)
    return np.clip(column, q_low, q_high)

# 对所有数值型列应用截断法（保留1%~99%分位数）
for col in numeric_cols:
    df[col] = winsorize_column(df[col])

# 方法2：删除法（若异常值比例极低，慎用！）
# df = df[(z_scores <= threshold).all(axis=1)]  # 删除所有列均为异常值的行

# =============================================================================
# 三、结果验证
# =============================================================================

# 8. 检查处理后的数据
print("\n【处理后缺失值统计】\n", check_missing_values(df))
print("\n【处理后数据示例】\n", df.head())